/*
 * MIT License
 *
 * Copyright (c) 2025 Mark·虎
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.hsxxherp.key.common.util;

import com.hsxxherp.key.common.error.ErrorCode;
import com.hsxxherp.key.common.exception.BusinessException;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.security.Security;

/**
 * SM4Util 工具类
 *
 * @author Mark·虎克 (2486970363@qq.com)
 */
public class SM4Util {

    private static final int BLOCK_SIZE = 16;

    static {
        // 添加 Bouncy Castle 安全提供者
        Security.addProvider(new BouncyCastleProvider());
    }

    private SM4Util() {
        // 私有构造函数，防止实例化
    }

    /**
     * ECB 模式加密
     *
     * @param plaintext 明文数据
     * @param key       密钥，长度为 16 字节
     * @return 加密后的十六进制字符串
     * @throws Exception 加密过程中可能抛出的异常
     */
    public static String encryptECB(byte[] plaintext, byte[] key) throws Exception {
        try {
            SM4Engine engine = new SM4Engine();
            PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(engine);
            cipher.init(true, new KeyParameter(key));

            byte[] output = new byte[cipher.getOutputSize(plaintext.length)];
            int length = cipher.processBytes(plaintext, 0, plaintext.length, output, 0);
            cipher.doFinal(output, length);

            return Hex.toHexString(output);
        } catch (Exception e) {
            throw new BusinessException("SM4加密失败", e).setCode(ErrorCode.CODE_100002);
        }
    }

    /**
     * ECB 模式解密
     *
     * @param ciphertext 加密后的十六进制字符串
     * @param key        密钥，长度为 16 字节
     * @return 解密后的明文数据
     * @throws Exception 解密过程中可能抛出的异常
     */
    public static byte[] decryptECB(String ciphertext, byte[] key) throws Exception {
        SM4Engine engine = new SM4Engine();
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(engine);
        cipher.init(false, new KeyParameter(key));

        byte[] input = Hex.decode(ciphertext);
        byte[] output = new byte[cipher.getOutputSize(input.length)];
        int length = cipher.processBytes(input, 0, input.length, output, 0);
        cipher.doFinal(output, length);

        return output;
    }

    /**
     * CBC 模式加密
     *
     * @param plaintext 明文数据
     * @param key       密钥，长度为 16 字节
     * @param iv        初始化向量，长度为 16 字节
     * @return 加密后的十六进制字符串
     * @throws Exception 加密过程中可能抛出的异常
     */
    public static String encryptCBC(byte[] plaintext, byte[] key, byte[] iv) {
        try {
            CBCBlockCipher blockCipher = new CBCBlockCipher(new SM4Engine());
            PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
            cipher.init(true, new ParametersWithIV(new KeyParameter(key), iv));

            byte[] output = new byte[cipher.getOutputSize(plaintext.length)];
            int length = cipher.processBytes(plaintext, 0, plaintext.length, output, 0);
            cipher.doFinal(output, length);

            return Hex.toHexString(output);
        } catch (Exception e) {
            throw new BusinessException("SM4加密失败", e).setCode(ErrorCode.CODE_100002);
        }
    }

    /**
     * CBC 模式解密
     *
     * @param ciphertext 加密后的十六进制字符串
     * @param key        密钥，长度为 16 字节
     * @param iv         初始化向量，长度为 16 字节
     * @return 解密后的明文数据
     * @throws Exception 解密过程中可能抛出的异常
     */
    public static byte[] decryptCBC(String ciphertext, byte[] key, byte[] iv) throws Exception {
        CBCBlockCipher blockCipher = new CBCBlockCipher(new SM4Engine());
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
        cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv));

        byte[] input = Hex.decode(ciphertext);
        byte[] output = new byte[cipher.getOutputSize(input.length)];
        int length = cipher.processBytes(input, 0, input.length, output, 0);
        cipher.doFinal(output, length);

        return output;
    }
}